/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package org.oimwrapper.testers;

import Thor.API.Operations.tcFormDefinitionOperationsIntf;
import Thor.API.Operations.tcFormInstanceOperationsIntf;
import Thor.API.Operations.tcObjectOperationsIntf;
import Thor.API.Operations.tcProvisioningOperationsIntf;
import Thor.API.tcResultSet;
import com.thortech.util.logging.Logger;
import com.thortech.xl.vo.ResourceData;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.junit.Test;
import org.oimwrapper.connectors.OIMAdapterBase;
import org.oimwrapper.connectors.OIMRemoteClientBase;
import org.oimwrapper.connectors.internal.OIMObjectFormUtilities;
import org.oimwrapper.connectors.internal.OIMUtilityGetter;

/**
 *
 */
public class ClientUserTester extends ClientBaseTester {

    private static final Logger logger = Logger.getLogger(ClientUserTester.class.getName());

    private static OIMAdapterBase apiBase;
    private OIMRemoteClientBase tester;
    
    private tcFormInstanceOperationsIntf formInstOps;
    private tcFormDefinitionOperationsIntf formDefOps;
    private tcObjectOperationsIntf objectOp;
    private OIMObjectFormUtilities objFormUtils;
    private tcProvisioningOperationsIntf provOps = null;
    
    

    @Test
    public void mainTest()
    {
        logger.debug("Starting ");
        OIMRemoteClientBase tester = null;
        logger.debug("Logging In ");
        try {
            tester = this.connect();
            apiBase = tester.getUtils();
            
            formInstOps = (tcFormInstanceOperationsIntf)apiBase.getUtility(Thor.API.Operations.tcFormInstanceOperationsIntf.class);
            formDefOps = (tcFormDefinitionOperationsIntf)apiBase.getUtility(Thor.API.Operations.tcFormDefinitionOperationsIntf.class);
            objectOp = (tcObjectOperationsIntf)apiBase.getUtility(Thor.API.Operations.tcObjectOperationsIntf.class);
            provOps = (tcProvisioningOperationsIntf)apiBase.getUtility(Thor.API.Operations.tcProvisioningOperationsIntf.class);
            objFormUtils = OIMUtilityGetter.getObjectFormUtilities(logger, objectOp,formInstOps, formDefOps);
            
        } catch (Exception ex) {
            logger.error("Exception",ex);
            return;
        }

        //logger.debug("RESOURCE A REQ OBJ");
        //provisionResource("GG10828","Resource A");
        //logger.debug("RESOURCE B NO REQ OBJ");
        //provisionResource("GG10828","Resource B");
        
        showObjectForUser("MC10415");
        //getObjectForm(3063L);
        
        //ResourceData rd = new ResourceData();
        //rd.setObiKey("3086");
        //rd.setOioKey(null);
        //rd.setOiuKey("46");
        //getFormInfo(rd,"Resource A");
        
        //rd.setObiKey("3087");
        //rd.setOioKey(null);
        //rd.setOiuKey("47");
        //getFormInfo(rd,"Resource B");
        //getObjectForm();
        
        //getObjectFormFields(3063L);
        
        //getResourceFormInfo("Resource A");
        //getResourceFormInfo("Resource B");
        
        //provisionWithObjectForm("CC11433","Resource C","UD_RESC_OC");
        logger.debug("All Done");
        
    }
    
    private void provisionWithObjectForm(String userId,String resName,String childTable)
    {
        Map<String,String> resParent = new HashMap<String,String>();
        List<Map<String,String>> resChildren = new ArrayList<Map<String,String>>();
        
        resC(resParent,resChildren);
        
        try
        {
            long objKey = this.apiBase.getResourceObject(resName);
            long usrKey = this.apiBase.getOimUser(userId);
            //"UD_RESC_OC"
            long childDefKey = objFormUtils.getObjectFormDefinitionKey(childTable);
            String defKey = Long.toString(childDefKey);
            Map[] childMaps = (Map[]) resChildren.toArray(new HashMap[0]);
            Map parmMap = new HashMap();
            parmMap.put(defKey,childMaps);
            long obi = provOps.createObjectInstanceWithObjectAndChildFormData(usrKey, objKey, resParent, parmMap);
            logger.debug("OBI:" + obi);
        }
        catch(Exception e)
        {
            logger.error("APIError",e);
        }
        
        
    }
    
    private void resC(Map<String,String> resaParent,List<Map<String,String>> resaChildren)
    {
        resaParent.put("UD_RESC_O_FAVORITE_COLOR","Blue");
        
        Map<String,String> child1 = new HashMap<String,String>();
        child1.put("UD_RESC_OC_ROLENAME","VENDOR_ROLE");
        resaChildren.add(child1);
        child1 = new HashMap<String,String>();
        child1.put("UD_RESC_OC_ROLENAME","CONTRACTOR_ROLE");
        resaChildren.add(child1);
    }
    
    private void getResourceFormInfo(String resourceName)
    {
        Map provision = null;
        Map approval = null;
        
        try
        {
            Map[] resourceInfo = this.apiBase.getResourceFormInfo(resourceName);
            for(int m=0;m<resourceInfo.length;m++)
            {
                Map ri = resourceInfo[m];
                String type = (String)ri.get("Process Definition.Type");
                if (type.equalsIgnoreCase("Provisioning"))
                    provision = ri;
                if (type.equalsIgnoreCase("Approval"))
                    approval = ri;
                logger.debug("RI:" + ri);
            }
            
            List<Map> fieldInfo = null;
            
            if (approval != null)
            {
                logger.debug("Get Object Fields");
                String defKey = (String)approval.get("FORMDEFKEY");
                String ver = (String)approval.get("FORMVER");
                fieldInfo = this.objFormUtils.getObjectFormFieldInfo(Long.parseLong(defKey), Integer.parseInt(ver));
                Map<String,List<Map>> childTableFieldInfo = objFormUtils.getObjectChildFormFieldInfo(Long.parseLong(defKey), Integer.parseInt(ver));
                logger.debug("Parent");
                logger.debug("" + fieldInfo);
                logger.debug("Children");
                logger.debug("" + childTableFieldInfo);
                return;
            }
            if (provision != null)
            {
                logger.debug("Get Provision Fields");
                String defKey = (String)provision.get("FORMDEFKEY");
                String ver = (String)provision.get("FORMVER");
                fieldInfo = this.apiBase.getProcessFormFieldInfo(Long.parseLong(defKey), Integer.parseInt(ver));
                Map<String,List<Map>> childTableFieldInfo = objFormUtils.getObjectChildFormFieldInfo(Long.parseLong(defKey), Integer.parseInt(ver));
                logger.debug("Parent");
                logger.debug("" + fieldInfo);
                logger.debug("Children");
                logger.debug("" + childTableFieldInfo);
                return;
            }
        }
        catch(Exception e)
        {
            logger.error("APIError",e);
        }
    }

    private void getObjectFormFields(long obi)
    {
        try
        {
            Map[] fields = objFormUtils.getObjectFormFieldInfo(obi);
            
            for(int f=0;f<fields.length;f++)
            {
                Map m = fields[f];
                logger.debug("Field:" + m);
            }
            
        }
        catch(Exception e)
        {
            logger.error("APIERROR",e);
        }
    }
    
    private void getObjectForm()
    {
        try
        {
            logger.debug("OBJECTS");
            tcResultSet rs = objectOp.findObjects(new HashMap());
            printResultSet(rs);
            logger.debug("FORMS");
            rs = formDefOps.findForms(new HashMap());
            printResultSet(rs);
            
        }
        catch(Exception e)
        {
            logger.error("APIERROR",e);
        }
    }
    private void showObjectForUser(String userId)
    {
        try
        {
            logger.debug("Get User Data for AA11698 ");
            Map user = apiBase.getOimUserData("AA11698");
            if (user == null)
            {
                logger.error("User Not Found ");
                return;
            }
            logger.debug("User Data:" + user);
            String userKey = (String)user.get("Users.Key");
            //Map[] objects = apiBase.getObjectsForUser("Resource B", Long.parseLong(userKey), true);
            Map[] objects = apiBase.getObjectsForUser(Long.parseLong(userKey), false);
            logger.debug("User Objects");
            if (objects != null)
            {
                for(Map object : objects)
                {
                    logger.debug("Object " + object);
                    //String procKeyStr = (String)object.get("Process Instance.Key");
                    //String procForm = (String)object.get("Process.Process Definition.Process Form Name");
                    //String objName = (String)object.get("Objects.Name");
                    //logger.debug("Object Name:" + objName + " PIK:" + procKeyStr + " Form " + procForm);
                    //showProcessData(object);
                    //showOpenTaksForUserProcess(Long.parseLong(procKeyStr));
                }
            }
        }
        catch(Exception e)
        {
            logger.error("Exception" ,e);
        }
    }
    private void showProcessData(Map object)
    {

        String procKeyStr = (String)object.get("Process Instance.Key");
        String procForm = (String)object.get("Process.Process Definition.Process Form Name");
        String objName = (String)object.get("Objects.Name");
        long procKey = Long.parseLong(procKeyStr);

        try
        {
            Map procVals = apiBase.getProcessFormValues(procKey);
            logger.debug("Proc Values " + procVals);
            String[] childTables = apiBase.getChildTables(procKey);

            for(String childTable : childTables)
            {
                Map[] children = apiBase.getProcessFormChildValues(procKey, childTable);
                if (children != null)
                {
                    for(Map child : children)
                    {
                        logger.debug("Children:" + child);
                    }
                }
            }
            
        }
        catch(Exception e)
        {
            logger.error("Exception",e);
            return;
        }
    }
    
    public void showOpenTaksForUserProcess(long processInstanceKey)
    {
        logger.debug("Open Tasks for User Process");
        try
        {
            tcProvisioningOperationsIntf provOps = 
                    (tcProvisioningOperationsIntf)apiBase.getUtility(Thor.API.Operations.tcProvisioningOperationsIntf.class);
            tcResultSet rs = provOps.getProcessDetail(processInstanceKey);
            
            if (rs == null || rs.getRowCount() <= 0)
            {
                logger.error("No Data");
                return;
            }
            
            int rows = rs.getRowCount();
            String[] headers = rs.getColumnNames();
            for(int i=0;i<rows;i++)
            {
                rs.goToRow(i);
                String status = rs.getStringValue("Status.Category");
                if (status.equalsIgnoreCase("pending"))
                    continue;
                logger.debug("Show Task " + i);
                for(int h=0;h<headers.length;h++)
                {
                    logger.debug(headers[h] + ":" + rs.getStringValue(headers[h]));
                }
            }
            
            
        }
        catch(Exception e)
        {
            logger.error("showOpenTaksForUserProcess",e);
        }
    }

    /*
     * get all the child entries for this process instance and remove the one that matches
     */
    private void removeChildProcessEntry(long procKey,String childTable,String childFldName,String value)
    {

        try
        {
            //Map procVals = apiBase.getProcessFormValues(procKey);
            //logger.debug("Proc Values " + procVals);
            Map[] children = apiBase.getProcessFormChildValues(procKey, childTable);
            if (children != null)
            {
                for(Map child : children)
                {
                    logger.debug("Children:" + child);
                    String val = (String)child.get(childFldName);
                    if (value.equalsIgnoreCase(val))
                    {
                        logger.debug("Found Child matching " + value);
                        apiBase.removeProcessDataChildValue(procKey, childTable, child);
                    }
                }
            }

        }
        catch(Exception e)
        {
            logger.error("Exception",e);
            return;
        }
    }
    
    
    public void provisionResource(String targetUser,String resName)
    {
        try
        {
            long objKey = this.apiBase.getResourceObject(resName);
            long usrKey = this.apiBase.getOimUser(targetUser);
            logger.debug("Provisioning Resource " + resName + " To " + targetUser);
            ResourceData rd = this.apiBase.provisionNewResource(targetUser, objKey);
            
            logger.debug("RD:" + rd.getObiKey() + ":" + rd.getOioKey() + ":" + rd.getOiuKey());
            
            //logger.debug("OBI:" + obi);
            //Map objectForm = this.objFormUtils.getObjectFormValues(obi, true, null);
            //logger.debug("ObjectForm:" + objectForm);
            
            long newProcessInstanceKey = this.apiBase.getProcessInstanceKey(Long.parseLong(rd.getObiKey()), usrKey);
            logger.debug("PIK FROM OBI:" + newProcessInstanceKey);
            if (newProcessInstanceKey == 0L)
            {
                // this is probably an object form for a request that needs to be filled in.
                long obi = Long.parseLong(rd.getObiKey());
                Map objectForm = this.objFormUtils.getObjectFormValues(obi, true, null);
                Map objectFields = this.objFormUtils.getObjectFormDisplayNames(obi);
                logger.debug("Got Object Form:" + objectForm);
                logger.debug("Got Object Form:" + objectFields);
                Map[] fields = objFormUtils.getObjectFormFieldInfo(obi);
                for(int f=0;f<fields.length;f++)
                {
                    Map m = fields[f];
                    logger.debug("Field:" + m);
                }
                // we get the values from this process forms children and use those
                // to populate the process form of the newly provisioned resource.
                // the child recs should have the ud field name and the value
                // and we can map then to the new object/process form
                //objFormUtils.setObjectFormValues(newProcessInstanceKey, objectForm);
            }
            else
            {
                // we have a valid process form we can populate.
                
                Map procForm = this.apiBase.getProcessFormValues(newProcessInstanceKey);
                Map procFields = this.apiBase.getProcessFormDisplayNames(newProcessInstanceKey);
                logger.debug("Got Process Form:" + procForm);
                logger.debug("Got Process Form:" + procFields);
                
                Map[] fields = this.apiBase.getProcessFormFieldInfo(newProcessInstanceKey);
                for(int f=0;f<fields.length;f++)
                {
                    Map m = fields[f];
                    logger.debug("Field:" + m);
                }
                // we get the values from this process forms children and use those
                // to populate the process form of the newly provisioned resource.
                // the child recs should have the ud field name and the value
                // and we can map then to the new object/process form
                //this.apiBase.setProcessFormValues(newProcessInstanceKey, data);
            }
            
           
        }
        catch(Exception e)
        {
            logger.error("APIError",e);
        }
    }
    
    public void getFormInfo(ResourceData rd,String resName)
    {
        logger.debug("RD:" + rd.getObiKey() + ":" + rd.getOioKey() + ":" + rd.getOiuKey());
        try
        {
            
                Map resource  = this.apiBase.getResourceAttributes(resName);
                logger.debug("Resource:" + resource);
                String objForm = (String)resource.get("Structure Utility.Table Name");
                if (objForm == null || objForm.trim().length() == 0)
                {
                    logger.debug("Process Form");
                    return;
                }
                if (objForm != null)
                {
                    
                    Map filter = new HashMap();
                    filter.put("Structure Utility.Table Name",objForm);
                    tcResultSet rs = formDefOps.findForms(filter);
                    String version = "";
                    String vlabel = "";
                    for(int i=0;i<rs.getRowCount();i++)
                    {
                        version = rs.getStringValue("SDK_CURRENT_VERSION");
                        vlabel = rs.getStringValue("CURRENT_SDL_LABEL");
                    }
                    int ver = Integer.parseInt(version);
                    logger.debug("Form Ver:" + ver + " Name:" + vlabel);
                    long objectFormDefKey = this.formInstOps.getObjectFormDefinitionKey(Long.parseLong(rd.getObiKey()));
                    int activeVer = this.formInstOps.getActiveVersion(objectFormDefKey);
                    logger.debug("formdefkey:" + objectFormDefKey + " ver:" + activeVer);
                    tcResultSet results = this.formDefOps.getFormFields(objectFormDefKey, ver);
                    Map result = new HashMap();
                    for (int i = 0; i < results.getRowCount(); i++) {
                        results.goToRow(i);
                        String field = results.getStringValue("Structure Utility.Additional Columns.Name");
                        String label = results.getStringValue("Structure Utility.Additional Columns.Field Label");
                        result.put(field, label);
                    }
                    logger.debug("result:" + result);
                    
                }
            
            
        }
        catch(Exception e)
        {
            logger.error("APIError",e);
        }
    }

}
